package libra;

import java.util.function.Function;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.Buildable;
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
import org.springframework.cloud.gateway.route.builder.PredicateSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder.Builder;
import org.springframework.cloud.gateway.route.builder.UriSpec;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MainEntry {
	public static void main(String[] args) {
		/*
		 * 启动Spring应用，返回一个ConfigurableApplicationContext的context对象，可以像原来一样从里面通过getbean等方法，获取对象
		 * run()传入的类，一定要是个用@SpringBootApplication注解标注的类，被@SpringBootApplication标注的类被解释为SpringBoot的主配置类。
		 * 当程序执行时，就应该运行该类的main方法来启动SpringBoot应用。
		 */
		ConfigurableApplicationContext cac = org.springframework.boot.SpringApplication.run(MainEntry.class, args);
	}
	
	/**
	 * Gateway除了在yml中配置路由routes，还可以通过编码的形式配置路由routes
	 * 如果存在多个路由，则都会进行断言判断，如果断言都为假->返回404，如果有断言为真->立即执行第一个为真的路由
	 * 
	 * 所有AbstractRoutePredicateFactory的子类均为内置的Predicate断言
	 * AbstractRoutePredicateFactory
	 * 		AfterRoutePredicateFactory
	 * 		BeforeRoutePredicateFactory
	 * 		BetweenRoutePredicateFactory
	 * 		CookieRoutePredicateFactory
	 * 		HeaderRoutePredicateFactory
	 * 		MethodRoutePredicateFactory
	 * 		PathRoutePredicateFactory
	 * 		QueryRoutePredicateFactory
	 * 		RemoteAddrRoutePredicateFactory
	 * 		HostRoutePredicateFactory
	 * 
	 * 		WeightRoutePredicateFactory
	 * 		CloudFoundryRouteServiceRoutePredicateFactory
	 * 		ReadBodyRoutePredicateFactory
	 * 		XForwardedRemoteAddrRoutePredicateFactory
	 * 	去掉后面的RoutePredicateFactory的方法名即为内置断言的提供实现
	 * 	例如between()即为BetweenRoutePredicateFactory提供的实现
	 * 
	 * 
	 * 所有AbstractGatewayFilterFactory的子类均为内置的Filter过滤
	 * 		AddRequestHeaderGatewayFilterFactory
	 * 		AddRequestParameterGatewayFilterFactory
	 * 		AddResponseHeaderGatewayFilterFactory
	 * 		RemoveRequestHeaderGatewayFilterFactory
	 * 		RemoveRequestParameterGatewayFilterFactory
	 * 		RemoveResponseHeaderGatewayFilterFactory
	 * 		DedupeResponseHeaderGatewayFilterFactory
	 * 		RedirectToGatewayFilterFactory
	 * 		RewritePathGatewayFilterFactory
	 * 
	 * 		SetRequestHeaderGatewayFilterFactory
	 * 		SetRequestHostHeaderGatewayFilterFactory
	 * 		SetResponseHeaderGatewayFilterFactory
	 * 		SetStatusGatewayFilterFactory
	 * 		SetPathGatewayFilterFactory
	 * 		StripPrefixGatewayFilterFactory
	 * 		PrefixPathGatewayFilterFactory

	 * 		RewriteResponseHeaderGatewayFilterFactory
	 * 		RewriteLocationResponseHeaderGatewayFilterFactory
	 * 
	 * 		SpringCloudCircuitBreakerFilterFactory
	 * 		JsonToGrpcGatewayFilterFactory
	 * 		MapRequestHeaderGatewayFilterFactory
	 * 		ModifyRequestBodyGatewayFilterFactory
	 * 		CacheRequestBodyGatewayFilterFactory
	 * 		ModifyRequestBodyGatewayFilterFactory
	 * 		ModifyResponseBodyGatewayFilterFactory
	 * 		PreserveHostHeaderGatewayFilterFactory
	 * 		RequestRateLimiterGatewayFilterFactory
	 * 		RetryGatewayFilterFactory
	 * 		SecureHeadersGatewayFilterFactory
	 * 		SaveSessionGatewayFilterFactory
	 * 		RequestHeaderToRequestUriGatewayFilterFactory
	 * 		RequestSizeGatewayFilterFactory
	 * 		RequestHeaderSizeGatewayFilterFactory
	 * 		TokenRelayGatewayFilterFactory
	 * 		FallbackHeadersGatewayFilterFactory
	 * 	去掉后面的RoutePredicateFactory的方法名即为内置断言的提供实现
	 * 	例如addResponseHeader()即为BetweenRoutePredicateFactory提供的实现
	 */
	// 测试Predicate、Filter基于yml配置的应用方式时，需要注释该RouteLocator_bean组件注册，否则会由于'/**'断言匹配影响测试
//	@Bean
//	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
//		Builder routes = builder.routes();
//		
//		/*
//		 * Route配置后的执行逻辑
//		 * 	访问：http://gatewayIp:gatewayPort/path_1/path_2/path_n
//		 * 		1.通过设置的Predicate断言，判断当前访问Gateway的请求是否满足匹配条件(path匹配、请求时间、ReqHeader头信息)。
//		 * 	 	 如果满足匹配条件，则执行该Route后续的Filter(过滤)[可选]、uri(真实ip地址)[必选]
//		 *  	2.如果当前Route设置的Filter过滤，则执行当前设置的Filter过滤逻辑
//		 *  	3.将访问Gateway的url中的ip:port，替换为uri(服务真实ip地址)
//		 *  最后实际访问：uri[http://ip:port]/path_1/path_2/path_n
//		 */
//		routes.route("/test", new Function<PredicateSpec, Buildable<Route>>() {
//			@Override
//			public Buildable<Route> apply(PredicateSpec p) {
//					   /*
//					    * 通过PathRoutePredicate(Path路径)断言，判断当前请求url是否符合/**。即所有请求均符合该条件
//					    */
//				return p.path("/**")
//						// 如果符合上述predicate断言，则执行该filter过滤
//						.filters( new Function<GatewayFilterSpec, UriSpec>() {
//							@Override
//							public UriSpec apply(GatewayFilterSpec f) {
//								/*
//								 * 通过StripPrefixGatewayFilter(截断请求前缀)过滤，对请求url进行前缀截断
//								 * 传入的int数值，代表url截断的层级数。
//								 * 例如：
//								 * 	访问gateway时，url为http://ip:port/path1/path2/path3/xxx
//								 * 	通过filter过滤stripPrefix(3)，则会从port开始截断/path1/path2/path3三个层级
//								 * 	然后实际访问的url为{uri}/xxx
//								 */
//								return f.stripPrefix(1);
//							}
//						} )
//						.uri("http://127.0.0.1:8080");
//			}
//		});
//		
//		/* 
//		 * 添加一个Route(路由),
//		 * 	包含'唯一ID'、'path断言匹配'、'实际对应的真实访问IP地址(ip:port)'。
//		 * 访问 http://127.0.0.1:20900/movie -> 跳转https://www.bilibili.com/movie
//		 * !!!：
//		 * 	如果存在多个路由，则都会进行断言判断，如果断言都为假->返回404，如果有断言为真->立即执行第一个为真的路由。
//		 * 	因此该路由需要放在最前面才会生效，否则会被Path匹配"/**"抢先匹配而失效。
//		 */
//		routes = routes.route("code_gateway_id",  
//				(r) -> { return r.path("/movie").uri("https://www.bilibili.com"); } );
//		
//		return routes.build();
//	}
}
